/*
 * Copyright 2002-2006 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package de.breitbeil.jbooking.domain;

import java.util.Date;

import org.springframework.core.closure.Constraint;
import org.springframework.rules.Rules;
import org.springframework.rules.constraint.CompoundConstraint;
import org.springframework.rules.constraint.GreaterThan;
import org.springframework.rules.constraint.GreaterThanEqualTo;
import org.springframework.rules.constraint.property.PropertiesConstraint;
import org.springframework.rules.constraint.property.PropertyConstraint;
import org.springframework.rules.support.DefaultRulesSource;

import de.breitbeil.jbooking.ui.form.BookingTemplateFormObject;
import de.breitbeil.jbooking.ui.form.ExportFormObject;
import de.breitbeil.jbooking.ui.form.FtpCalendarFormObject;
import de.breitbeil.jbooking.ui.form.SaveCalendarFormObject;

/**
 * This class is a source for validation rules associated with the domain objects in this application. This clas is
 * wired into application via the application context configuration like this:
 * 
 * <pre>
 *    &lt;bean id=&quot;rulesSource&quot; 
 *        class=&quot;de.breitbeil.jbooking.domain.SimpleValidationRulesSource&quot;/&gt;
 * </pre>
 * 
 * With this configuration, validating forms will interrogate the rules source for rules that apply to the class of a
 * form object (in this case, that's objects of type {@link Contact}.
 * @author Larry Streepy
 */
public class SimpleValidationRulesSource extends DefaultRulesSource {

	/**
	 * Basic name validator. Note that the "alphabeticConstraint" argument is a message key used to locate the message
	 * to display when this validator fails.
	 */
	private final Constraint NAME_CONSTRAINT = all(new Constraint[] { required(), minLength(2),
			regexp("[-'.a-zA-Z ]*", "alphabeticConstraint") });

	/** Email validator, simply tests for x@y, wrap in ()? so it is optional */
	private final Constraint EMAIL_CONSTRAINT = all(new Constraint[] { regexp("([-_a-zA-Z0-9.]+@[-_a-zA-Z0-9.]+)?",
			"emailConstraint") });

	/** Phone number validator, must be numerical with separator */
	private final Constraint PHONE_CONSTRAINT = all(new Constraint[] { regexp("[0-9./-\\\\+ ]*",
			"phoneConstraint") });
	
	private final Constraint YEAR_CONSTRAINT = all(new Constraint[] { required(), minLength(4), maxLength(4) });

	/**
	 * Construct the rules source. Just add all the rules for each class that will be validated.
	 */
	public SimpleValidationRulesSource() {
		super();

		// Add the rules specific to the object types we manage
		addRules(createPersonRules());
		addRules(createBookingRules());
		addRules(createEventRules());
		
		addRules(createSaveCalendarFormObject());
		addRules(createFtpCalendarFormObject());
		addRules(createBookingTemplateFormObject());
		addRules(createExportFormObject());
	}

    /**
	 * Construct the rules that are used to validate a Person domain object.
	 * @return validation rules
	 * @see Rules
	 */
	private Rules createPersonRules() {
		// Construct a Rules object that contains all the constraints we need to apply
		// to our domain object. The Rules class offers a lot of convenience methods
		// for creating constraints on named properties.

		return new Rules(Person.class) {
			protected void initRules() {
				//add("firstname", NAME_CONSTRAINT);
				//add("lastname", NAME_CONSTRAINT);
				//add(not(eqProperty("firstName", "lastName")));

				add("email", EMAIL_CONSTRAINT);
				add("homePhone", PHONE_CONSTRAINT);
				add("workPhone", PHONE_CONSTRAINT);
			}
		};
	}
	
   /**
     * Construct the rules that are used to validate a Booking domain object.
     * @return validation rules
     * @see Rules
     */
    private Rules createBookingRules() {
        return new Rules(Booking.class) {
            protected void initRules() {
                addRequired("bookingType");
                addRequired("person");
                add(new PropertiesConstraint("to", new GreaterThanEqualTo(), "from"));
            }
        };
    }
    
    /**
     * Construct the rules that are used to validate a Event domain object.
     * @return validation rules
     * @see Rules
     */
    private Rules createEventRules() {
        return new Rules(Event.class) {
            protected void initRules() {
                addRequired("deadline");
            }
        };
    }
    
    private Rules createSaveCalendarFormObject() {
        return new Rules(SaveCalendarFormObject.class) {
            protected void initRules() {
                addRequired("suffix");
                addRequired("filename");
                addRequired("firstDisplayedDay");
            }
        };
    }
    
    private Rules createFtpCalendarFormObject() {
        return new Rules(FtpCalendarFormObject.class) {
            protected void initRules() {
                addRequired("suffix");
                addRequired("remoteFile");
                addRequired("firstDisplayedDay");
            }
        };
    }
    
    private Rules createBookingTemplateFormObject() {
        return new Rules(BookingTemplateFormObject.class) {
            protected void initRules() {
                addRequired("template");
                addRequired("output");
                addRequired("person");
            }
        };
    }
    
    private Rules createExportFormObject() {
        return new Rules(ExportFormObject.class) {
            protected void initRules() {
                addRequired("output");
            }
        };
    }

}
